// Copyright (C) Calum Grant 2008

namespace dynamic
{
	namespace internal
	{
		/// A class used to implement a variant.
		/** @param Base		The base class of all types stored in the variant.
			@param Bytes	The size in bytes used to store the data.
			\ingroup mem
			*/
		template<typename Base, std::size_t Bytes>
		class DYNAMIC_API variant
		{
			union { cg::max_aligned m_aligned; char m_data[Bytes]; };

		public:
			/// Retrieves the value stored in the variant.
			Base *get() 
			{ 
				return reinterpret_cast<Base*>(m_data); 
			}

			/// Retrieves the value stored in the variant (const version).
			const Base * get() const 
			{ 
				return reinterpret_cast<const Base*>(m_data); 
			}

			/// Access the value stored in the variant.
			Base * operator->() 
			{ 
				return get(); 
			}

			/// Access the value stored in the variant (const version).
			const Base * operator->() const 
			{ 
				return get(); 
			}

			/// Access the value stored in the variant.
			Base & operator*() 
			{ 
				return *get(); 
			}

			/// Access the value stored in the variant (const version).
			const Base & operator*() const 
			{ 
				return *get(); 
			}

			/// Assigns a value to the variant.
			/** T must fit into the variant.  
				T must be a subtype of Base
				T should have a virtual destructor (not validated)
				T must have a copy_to method
			*/
			template<typename T>
			variant(const T & t) 
			{
				cg::staticassert<sizeof(T) <= Bytes>();
				static_cast<const Base&>(t);
				t.copy_to(m_data);
			}

			/// Destroys the contents of the variant.
			~variant()
			{
				get()->~Base();
			}

			/// Copies the other variant into the object.
			variant(const variant & other)
			{
				other.get()->copy_to(get());
			}

			/// Assigns from another variant.
			variant & operator=(const variant & other)
			{
				if(this != &other)
				{
					get()->~Base();
					other.get()->copy_to(get());	// Must not throw
				}
				return *this;
			}

			/// Assigns from another value.
			template<typename T>
			variant & operator=(const T & other)
			{
				cg::staticassert<sizeof(T) <= Bytes>();
				static_cast<const Base&>(other);
				get()->~Base();
				other.copy_to(get());	// Must not throw
				return *this;
			}
		};


		/// The interface which the contents of a variant should implement.
		class DYNAMIC_API variant_base
		{
		public:
			virtual ~variant_base() { }

			/// Copies the value to another location (in-place copy).
			virtual void copy_to(void*) const=0;
		};
	}

	/// \todo Hard coded size needs to change
	/// A variant which holds a var_impl.
	typedef dynamic::internal::variant<var_impl, 16> var_variant;
}
